/** Hide & Seek Eventos Ares Games
 * www.ares-games.net
 * by AsuS
 * Ares Games Community
 */
package com.l2jserver.gameserver.model.entity;

import java.io.IOException;

import com.l2jserver.Config;
import com.l2jserver.gameserver.Announcements;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.datatables.NpcTable;
import com.l2jserver.gameserver.datatables.SpawnTable;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.actor.instance.L2HaSEventManagerInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.entity.HideAndSeekDataParser.Action;
import com.l2jserver.gameserver.model.olympiad.Olympiad;
import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
import com.l2jserver.util.Rnd;

import javolution.util.FastList;

/**
 * @author BiggBoss
 */
public class HideAndSeek {

	public static FastList<L2PcInstance> _playersInEvent = new FastList<L2PcInstance>();
	public static FastList<L2PcInstance> _disconnectedPlayers = new FastList<L2PcInstance>();
	
	private static final String REG_ANNOUNCE = "Hide and seek event is now active. Type .joinhs or meet the npc to participe";
	private static final String START_ANNOUNCE = "Hide and seek event has started!. Listen the clues to find the hide npc!";

	private static boolean _isRegistering;
	private static boolean _isStarted;
	private static boolean _haveWinner;
	
	private static int _lastZone = 0;
	
	public static int _timeLeft;
	
	private static HideAndSeekDataParser _hasDp;
	
	private static L2Spawn _spawn, _regSpawn;
	private static L2HaSEventManagerInstance _hideNpc, _regNpc;
	
	private HideAndSeek() { }
	
	public static synchronized boolean addPlayer(L2PcInstance pc) {
		if(!_playersInEvent.contains(pc)) {
			_playersInEvent.add(pc);
			return true;
		}
		else
			return false;
	}
	
	public static synchronized boolean removePlayer(L2PcInstance pc) {
		if(_playersInEvent.contains(pc)) {
			_playersInEvent.remove(pc);
			return true;
		}
		else
			return false;
	}
	
	private static void spawnHideNpc() {
		L2NpcTemplate npc = NpcTable.getInstance().getTemplate(_hasDp.getNpcId());
		
		try {
			_spawn = new L2Spawn(npc);
			_spawn.setAmount(1);
			_spawn.setLocx(_hasDp.getX());
			_spawn.setLocy(_hasDp.getY());
			_spawn.setLocz(_hasDp.getZ());
			_spawn.setRespawnDelay(1);
			SpawnTable.getInstance().addNewSpawn(_spawn, false);
		_spawn.init();
            _hideNpc = (L2HaSEventManagerInstance) _spawn.getLastSpawn();
            _hideNpc.setCurrentHp(_hideNpc.getMaxHp());
            _hideNpc.setTitle("Find Me!");
            _hideNpc.hideMe(true);
            _hideNpc.isAggressive();
            _hideNpc.decayMe();
            _hideNpc.spawnMe(_spawn.getLastSpawn().getX(), _spawn.getLastSpawn().getY(), _spawn.getLastSpawn().getZ());

		} 
		catch (Throwable e) {
			e.printStackTrace();
		}	
	}
	
	private static void spawnRegisterNpc() {
		L2NpcTemplate npc = NpcTable.getInstance().getTemplate(Config.HAS_NPC);
		
		try {
			_regSpawn = new L2Spawn(npc);
			_regSpawn.setAmount(1);
			_regSpawn.setLocx(Config.HAS_NPC_COORDS[0]);
			_regSpawn.setLocy(Config.HAS_NPC_COORDS[1]);
			_regSpawn.setLocz(Config.HAS_NPC_COORDS[2]);
			_regSpawn.setRespawnDelay(1);
			SpawnTable.getInstance().addNewSpawn(_regSpawn, false);
			_regSpawn.init();
            _regNpc = (L2HaSEventManagerInstance) _regSpawn.getLastSpawn();
            _regNpc.setCurrentHp(_regNpc.getMaxHp());
            _regNpc.setTitle("Hide & Seek Manager");
            _regNpc.isAggressive();
            _regNpc.decayMe();
            _regNpc.spawnMe(_regSpawn.getLastSpawn().getX(), _regSpawn.getLastSpawn().getY(), _regSpawn.getLastSpawn().getZ());
		} 
		catch (Throwable e) {
			e.printStackTrace();
		}	
	}

	public static void setIsRegistering(boolean b) {
		_isRegistering = b;
	}
	
	public static boolean isRegistering() {
		return _isRegistering;
	}
	
	public static void setStarted(boolean b) {
		_isStarted = b;
	}
	
	public static boolean isStarted() {
		return _isStarted;
	}
	
	public static void setWinner(boolean b) {
		_haveWinner = b;
	}
	
	public static boolean haveWinner() {
		return _haveWinner;
	}
	
	private static void clearNpc() {
		_spawn.stopRespawn();
		_spawn = null;
		_regSpawn.stopRespawn();
		_regSpawn = null;
	}
	
	public static void rewardWinner(L2PcInstance player) {
		if(player != null) {
			if(Config.HAS_SINGLEREWARD)
				player.addItem("Hide & Seek event", Config.HAS_REWARD, Config.HAS_REWARD_AMOUNT, player, true);
			else
				player.addItem("Hide & Seek event", _hasDp.getReward(), _hasDp.getRewardAmount(), player, true);
		}
		else return;
	}
	
	private static final void clearMe() {
		for(L2PcInstance p : _playersInEvent) {
			if(p == null) continue;
			
			p.setTitle("");
			p.getAppearance().setTitleColor(0xFFFFFF);
			p.setIsInHASEvent(false);
			p.broadcastUserInfo();
		}
		_playersInEvent.clear();
		_haveWinner = false;
		_hasDp = null;
		clearNpc();
	}
	
	private static void finishEventTask() throws IOException {
		_hasDp.stopClueTask();
		_hasDp.LastZone(Action.SAVE);
		_regNpc.deleteMe();
		_hideNpc.deleteMe();
		clearMe();
	}
	
	private static void finishDueLack() {
		Announcements.getInstance().announceToAll("The event was cancelled due the lack of participation");
		_regNpc.deleteMe();
		_regSpawn.stopRespawn();
		_regNpc = null;
	}
		
	public static void start() throws InterruptedException, IOException {
		long regPeriod = Config.HAS_REGPERIOD * 60 * 1000;
		long gamePeriod = Config.HAS_GAMETIME * 60 * 1000;
		long startRegTime = System.currentTimeMillis();
		int delay;
		
		Announcements.getInstance().announceToAll(REG_ANNOUNCE);
		setIsRegistering(true);
		
		System.out.println("Starting Hide And Seek event!");
		spawnRegisterNpc();
		while(startRegTime + regPeriod > System.currentTimeMillis()) {
			delay = (int) ((startRegTime + regPeriod) - System.currentTimeMillis());
			short inSec = (short) (delay / 1000);
			
			if(Config.HAS_REGPERIOD > 10 ){
				while(delay > 599000) {
					for(int i = 0; i< regPeriod - delay; i = i + 180000) {
						Announcements.getInstance().announceToAll("Hide & Seek: " +
								((i - regPeriod) / 1000) / 60 + " mins left to join the event");
						Thread.sleep(1000);
					}
				}
			}
			
			switch(inSec) {
			
			case 420:
				Announcements.getInstance().announceToAll("Hide & Seek: 7 mins left to join the event");
				Thread.sleep(1000);
				break;
			case 180:
				Announcements.getInstance().announceToAll("Hide & Seek: 3 mins left to join the event");
				Thread.sleep(1000);
				break;
			case 60:
				Announcements.getInstance().announceToAll("Hide & Seek: 1 mins left to join the event");
				Thread.sleep(1000);
				break;
				default:
			}
		}
		
		{
			setIsRegistering(false);
			if(_playersInEvent.isEmpty()) {
				finishDueLack();
				return;
			}

			Announcements.getInstance().announceToAll("The Registration period has ended");
			Announcements.getInstance().announceToAll(START_ANNOUNCE);
			setStarted(true);
		}
		System.out.println("Starting Hide And Seek Game Event!");
		
		ThreadPoolManager.getInstance().executeTask(new Runnable() {
			public void run() {
				try {
					short zone = 0;
					if(Config.HAS_RANDOM) {
						zone = (short) Rnd.get(HideAndSeekDataParser._maxZones);
						
						while(zone == _lastZone) {
							zone = (short) Rnd.get(HideAndSeekDataParser._maxZones);
						}
						_hasDp = new HideAndSeekDataParser(zone);
					}
					else {
						_hasDp = new HideAndSeekDataParser();
						_hasDp.LastZone(Action.READ);
					}
							
					for(L2PcInstance p : _playersInEvent) {
						if(p == null) continue;
						
						if(Olympiad.getInstance().isRegistered(p)) {
							removePlayer(p);
							p.sendMessage("Removed due Olympiad");
							continue;
						}
						else if(TvTEvent.isPlayerParticipant(p.getObjectId())) {
							removePlayer(p);
							p.sendMessage("Removed due TvT");
							continue;
						}
						else if(p.getKarma() > 0 || p.isCursedWeaponEquipped()) {
							removePlayer(p);
							p.sendMessage("Removed due Karma");
							continue;
						}
						
								
						p.setTitle("Hide And Seek");
						p.getAppearance().setTitleColor(0x0000FF);
						p.setIsInHASEvent(true);
						p.broadcastUserInfo();
					}
					System.out.println("Choosed zone: "+zone);
					System.out.println("Finished Set up task!");
					spawnHideNpc();
				_hasDp.startClueTask();
				}
				catch(Exception e) {
					e.printStackTrace();
				}
			}
		});
		
		long startGamePeriod = System.currentTimeMillis();
		while(startGamePeriod + gamePeriod > System.currentTimeMillis()) {			
			
			delay = (int) ((startGamePeriod + gamePeriod) - System.currentTimeMillis());
			short inSecs = (short) (delay / 1000);
			_timeLeft = delay;
			
			if(haveWinner()) {
				finishEventTask();
				return;
			}
			
			if(Config.HAS_REGPERIOD > 10 ){
				while(delay > 599000) {
					for(int i = 0; i< gamePeriod - delay; i = i + 180000) {
						Announcements.getInstance().announceToAll("Hide & Seek: " +
								((i - gamePeriod) / 1000) / 60 + " mins left to finish the event");
					}
				}
			}
			
			switch(inSecs) {
			
			case 420:
				Announcements.getInstance().announceToAll("Hide & Seek: 7 mins left to finish the event");
				Thread.sleep(1000);
				break;
			case 180:
				Announcements.getInstance().announceToAll("Hide & Seek: 3 mins left to finish the event");
				Thread.sleep(1000);
				break;
			case 60:
				Announcements.getInstance().announceToAll("Hide & Seek: 1 mins left to finish the event");
				Thread.sleep(1000);
				break;
			}
		}
		setStarted(false);
		_lastZone = _hasDp.getPlaceId();
		if(!haveWinner()) 
			Announcements.getInstance().announceToAll("Hide and Seek event ends with no winner.");

		Announcements.getInstance().announceToAll("The hide place was: "+_hasDp.getZoneName());
		{	
			finishEventTask();
			System.out.println("Ending Hide And See. Data cleared.");
		}
	}
}
